package com.bjc.netty.simple;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

/**
 * @program: nettypro
 * @description:
 * @author: bjc
 * @create: 2021-09-07 20:13
 */
public class NettyServer {

    public static void main(String[] args) throws InterruptedException {
        //1.创建两个线程组bossGroup
        //2.bossGroup 只是连接请求，真正的和客户端业务处理，会交给workerGroup完成
        //3.两个都是无线循环
        //4.bossGroup 和 workerGroup 含有的子线程（NioEventLoop）的个数
        //默认实际cpu核数*2
        NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);  //设置bossgroup数量为1
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            //创建服务器端的启动对象，配置参数
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup,workerGroup)//设置两个线程组
                    .channel(NioServerSocketChannel.class)//使用NioSocketChannel
                    .option(ChannelOption.SO_KEEPALIVE,true)//设置保持活动连接状态
                    .handler(null)   //handler对应bossGroup生效  childHandler对应workerGroup生效
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        //给pipeline设置处理器
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            System.out.println("客户端socketchannel hashcode = " + ch.hashCode());
                            //解决耗时的操作的方案三
                            //可以使用一个集合器管理SocketChannel,在推送消息时，
                            // 可以将业务加入到各个channel对应的NIOEventLoop的taskQueue 或者scheduleTaskQueue

                            ch.pipeline().addLast(new NettyServerHandler());
                        }
                    }); //给我们的workerGroup的EventLoop 对应的管道设置处理器
            System.out.println("------服务器 is ready....");
            //绑定一个端口并同步，生成了一个ChannelFuture对象
            // 启动服务器（并绑定端口）  sync()等待异步操作执行完毕
            ChannelFuture cf = bootstrap.bind(6668).sync();

            //给cf注册监听器 监听我们关心的事件
            cf.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    if (cf.isSuccess()){
                        System.out.println("监听端口 6668 成功");
                    }else {
                        System.out.println("监听端口 6668 失败");
                    }
                }
            });

            //对关闭通道进行监听
            cf.channel().closeFuture().sync();
        }finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}
